// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF

// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO

// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A

// PARTICULAR PURPOSE.

//

// Copyright (c) Microsoft Corporation. All rights reserved.


#ifndef _SAMPLE_AUTHENTICATOR_EAPMETHOD_H_
#define _SAMPLE_AUTHENTICATOR_EAPMETHOD_H_

#pragma once

#include <windows.h>
#include "eaptypes.h"
#include "eapmethodtypes.h"
#include "EapMethodAuthenticatorApis.h"
#include "lmcons.h"     // <UNLEN, PWLEN>


/// This Sample DLL sends a simple challenge request from server -> client.
const char STRING_CHALLENGE_MESSAGE[] = "send password";

/// Byte length of simple challenge request.
const size_t STRING_LENGTH_CHALLENGE_MESSAGE = sizeof(STRING_CHALLENGE_MESSAGE);

/// The # of attributes we need to add during authentication.
/// (Attributes: username, password)
const DWORD ATTRIBUTE_COUNT_AUTHENTICATION = 2;

/// Following are required for registering Eap Authenticator Method with EapHost.
const wchar_t authFriendlyName[] = L"AuthenticatorFriendlyName";
const wchar_t authDllPath[] = L"AuthenticatorDllPath";
const wchar_t properties[] = L"Properties";
const wchar_t authFriendlyNameValue[] = L"SdkAuthenticatorEapMethod";
const DWORD propertiesValue = 0x280000; ///< eapPropMppeEncryption (0x80000) & eapPropSupportsConfig (0x200000)
const wchar_t authMethodDllName[] = L"ServerSdkMethodDll.dll"; 

const DWORD AUTH_SUCCESS = 0;
const DWORD AUTH_FAILURE = 1;

typedef struct _EAP_NAME_DIALOG
{
    WCHAR               awszIdentity[ UNLEN + 1 ];      ///< A string buffer which will contain the authenticating user's username.
    WCHAR               awszPassword[ PWLEN + 1 ];      ///< A string buffer which will contain the authenticating user's password.
} EAP_NAME_DIALOG;

typedef struct _USER_DATA_BLOB
{
	DWORD eapTypeId;
	EAP_NAME_DIALOG eapUserNamePassword;
}USER_DATA_BLOB;


/// Enum: States within the EAP state machines used by this EAP Authenticator Dll.
typedef enum _MYSTATE 
{
    MYSTATE_Initial,
    MYSTATE_ReqSent,
} MYSTATE;


/**
  * EAP working buffer.
  *
  * This structure contains all persistent data that the EAP method needs to
  * operate.  The data buffer is created inside EapMethodAuthenticatorBeginSession(), 
  * persists through the entire authentication session, and is released inside 
  * EapMethodAuthenticatorEndSession().
  */
typedef struct _EAPCB 
{
	LPVOID              pWorkBuffer;              ///< Pointer to self -- a pointer to the memory buffer containing this instance of the structure.
	DWORD              fFlags;                        ///< One or more flags that quantify the authentication process.
	MYSTATE            EapState;                   ///< Current state within EAP state machine.
	DWORD              dwResult;                   ///< The overall result of the authentication attempt.

	EapAttributes*    pEapAttributes;          
	DWORD             dwSizeofConnectionData;      ///< Size of Connection Data
	PBYTE                pConnectionData;                     ///< Pointer to Connection Data
	DWORD             dwMaxSendPacketSize;         ///< Max Size of EAP packet to send back.

	CHAR                aszIdentity[ UNLEN + 1 ]; ///< A string buffer which will contain the authenticating user's username, once it is known.
	CHAR                aszPassword[ PWLEN + 1 ]; ///< A string buffer which will contain the authenticating user's password, once it is known.
	
	EapAttributes*   pUserAttributes;          ///< Local pointer to EAP attributes that contains UserName and Password and may be sent to the authenticator for authentication..
	EapAttributes*   pMPPEKeyAttributes;  ///< Local pointer to the MPPE key EAP attributes generated by this EAP provider after a successful authentication transaction has been performed.
}EAPCB;

//
// EAP Functions whose function pointer is returned back in EapMethodAuthenticatorGetInfo().
//

DWORD SdkEapMethodAuthenticatorInitialize(
         IN EAP_METHOD_TYPE* pEapType, 
         OUT EAP_ERROR** ppEapError
         );

DWORD SdkEapMethodAuthenticatorBeginSession(
      // Flags to qualify the authentication process.
      IN DWORD dwFlags,
      // Identity of the user being authenticated
      IN LPCWSTR pwszIdentity,
      // Pointer to an array of attributes. This array contains attributes that 
      // describe the entity being authenticated. 
      IN const EapAttributes* const pAttributeArray,
      // Specifies the size in bytes of the data pointed to by pConnectionData. 
      // If pConnectionData is NULL, this member is zero. 
      IN DWORD dwSizeofConnectionData,
      // Pointer to connection data received from the authentication protocol's 
      // configuration user interface.
      IN const BYTE* const pConnectionData,
      // This is the maximum size of an eap packet that the authenticator can send.
      IN DWORD dwMaxSendPacketSize,
      // The session handle that identifies the current authentication session.
      OUT EAP_SESSION_HANDLE* pSessionHandle,
      // On an unsuccessful call, this will contain any error information about
      // the failure. This will be null on a successful call.
      OUT EAP_ERROR** pEapError
      );

DWORD SdkEapMethodAuthenticatorUpdateInnerMethodParams(
      // context handle as returned from a successful call to 
      // EapAuthenticatorBeginSession
      IN EAP_SESSION_HANDLE sessionHandle,
      IN DWORD dwFlags,
      IN CONST WCHAR* pwszIdentity,
      // Pointer to an array of attributes. This array contains attributes that 
      // describe the entity being authenticated. 
      IN const EapAttributes* const pAttributeArray,
      // On an unsuccessful call, this will contain any error information about
      // the failure. This will be null on a successful call.
      OUT EAP_ERROR** pEapError         
      );


// The authenticator calls this any time it receives a packet that the eaphost
// needs to process. This should be called only after a successful call to
// EapAuthenticatorBeginSession.
DWORD SdkEapMethodAuthenticatorReceivePacket(
         // context handle as returned from a successful call to 
         // EapAuthenticatorBeginSession
         IN EAP_SESSION_HANDLE sessionHandle,
         // Specifies the size, in bytes, of the buffer pointed to by 
         // pReceivePacket
         IN DWORD cbReceivePacket,
         // Pointer to a buffer that contains the incoming EAP data received by 
         // the supplicant.
         IN const EapPacket* const pReceivePacket,
         // This enumeration tells the supplicant to take an appropriate action.
         // The supplicant will typically look at this action and either call 
         // another method on eaphost or do something else on its own.
         OUT EAP_METHOD_AUTHENTICATOR_RESPONSE_ACTION* pEapOutput,
         // On an unsuccessful call, this will contain any error information about
         // the failure. This will be null on a successful call.      
         OUT EAP_ERROR** pEapError
         );

DWORD SdkEapMethodAuthenticatorSendPacket(
         // context handle as returned from a successful call to 
         // EapHostAuthenticatorBeginSession
         IN EAP_SESSION_HANDLE sessionHandle,
         // Id to use when constructing the SendPacket
         IN BYTE bPacketId,
         // Specifies the limit on the size, in bytes, on the packet generated
         // by eaphost. On a successful return, this will contain the size of the 
         // data added by the eap module.
         OUT DWORD* pcbSendPacket,
         // Pointer to a buffer that is allocated by the client and populated
         // by the eap module. The value of the incoming buffer is ignored and
         // the method populates it from the beginning of the buffer.
         OUT EapPacket* pSendPacket,
         // Timeout option for sending the packet
         OUT EAP_AUTHENTICATOR_SEND_TIMEOUT* pTimeout,
         // On an unsuccessful call, this will contain any error information about
         // the failure. This will be null on a successful call.
         OUT EAP_ERROR** pEapError
         );

  // Returns an array of attributes that the caller needs to act on.
  // The supplicant will call this when a call to 
  // EapHostAuthenticatorProcessRequestPacket returns EapHostAuthenticatorResponseRespond. 
DWORD SdkEapMethodAuthenticatorGetAttributes(
      // context handle as returned from a successful call to 
      // EapHostAuthenticatorBeginSession
      IN EAP_SESSION_HANDLE sessionHandle,
      // Array of attributes that the caller needs to act on.
      OUT EapAttributes* pAttribs,
      OUT EAP_ERROR** pEapError
      );

   // Sets an array of attributes that the caller wants the eap method to act 
   // on. 
DWORD SdkEapMethodAuthenticatorSetAttributes(
      // context handle as returned from a successful call to 
      // EapHostAuthenticatorBeginSession
      IN EAP_SESSION_HANDLE sessionHandle,
      IN const EapAttributes* const pAttribs,
      // This enumeration tells the supplicant to take an appropriate action.
      // The supplicant will typically look at this action and either call 
      // another method on eaphost or do something else on its own.
      OUT EAP_METHOD_AUTHENTICATOR_RESPONSE_ACTION* pEapOutput,
      // On an unsuccessful call, this will contain any error information about
      // the failure. This will be null on a successful call.      
      OUT EAP_ERROR** ppEapError
      );

   // The authenticator will call this on completion of an authentication. This 
   // can happen in any of the following scenarios:
   // 1. A call to EapHostAuthenticatorReceivePacket returned 
   //    EAP_HOST_AUTHENTICATOR_RESPONSE_SUCCESS or EAP_HOST_AUTHENTICATOR_RESPONSE_FAILURE
   //    Even if the action returned above was a success, the authenticator can choose to call
   //    this method with a failure.
   // 2. The server can choose to terminate an authentication with a failure in the middle of
   //    an authentication.
DWORD SdkEapMethodAuthenticatorGetResult(
      // context handle as returned from a successful call to 
      // EapHostPeerBeginSession
      IN EAP_SESSION_HANDLE sessionHandle,
      // A structure that indicates the result and any state that the 
      // supplicant needs to save for future authentications.
      OUT EAP_METHOD_AUTHENTICATOR_RESULT* ppResult, 
      // On an unsuccessful call, this will contain any error information about
      // the failure. This will be null on a successful call.      
      OUT EAP_ERROR** pEapError         
      );

   // Ends the authentication session. This cleans up any state that the eap 
   // method or eaphost might be keeping.
DWORD SdkEapMethodAuthenticatorEndSession(
      // context handle as returned from a successful call to 
      // EapHostPeerBeginSession. This will be set to NULL on a successful call.
      IN EAP_SESSION_HANDLE sessionHandle, 
      // On an unsuccessful call, this will contain any error information about
      // the failure. This will be null on a successful call.      
      OUT EAP_ERROR** ppEapError
   );

DWORD SdkEapAuthenticatorShutdown(
         IN EAP_METHOD_TYPE* pEapType, 
         OUT EAP_ERROR** ppEapError
         );


//
// Helper Functions
//

/**
  * MakeRequestMessage() helper function: Construct a request message
  *
  * This function builds the EAP-Challenge message(s) sent to the client.
  *
  *
  * @param  pwb          [in]  Pointer to the work buffer.
  *
  * @param bPacketId [in] PacketId to be used in the EapChallenge Method.
  *
  * @param  pSendPacket     [out] Pointer to a EapPacket structure. The
  *                            authentication protocol can use this structure
  *                            to specify a packet to send.
  *
  * @param  pcbSendPacket    [out]  Specifies the size, in bytes, of the buffer
  *                            pointed to by pSendPacket.
  *
  *
  * @return If the function succeeds, the return value is NO_ERROR.
  */
DWORD
MakeRequestMessage(
    IN  EAPCB*           pwb,
    IN BYTE bPacketId,
    OUT EapPacket *pSendPacket,
    OUT DWORD *  pcbSendPacket
);

/**
  * GetPasswordFromResponse() helper function: Parse a response packet to extract
  * the password.
  *
  * This function handles reading the EAP client's response packet.  It
  * obtains the user's password, to use when authenticating the user.
  *
  *
  * @param  pReceiveBuf  [in]  Pointer to a EapPacket structure that
  *                                          contains a received packet.
  *
  * @param  pszPassword  [out] Pointer to a buffer, into which the password
  *                                           will be copied.  The caller is responsible for
  *                                           allocating & freeing this buffer.
  *
  * @param size [in,out]             size of the password
  *
  * @return If the function succeeds, the return value is NO_ERROR.
  */
DWORD
GetPasswordFromResponse(
    IN const BYTE* const pReceivePacket,
    OUT __out_bcount(size)  CHAR*           pszPassword,
    size_t &size
);

/**
  * MakeAuthenticationAttributes() helper function: Build authentication
  * attributes to be sent to the authentication provider.
  *
  * This function wraps the received username & password into EAP
  * authentication attributes.  The authentication provider will process these
  * attributes, determine whether the authentication succeeded or failed.
  *
  *
  * @param  szUserName    [in]  The username received from the EAP client.
  *
  * @param  szPassword    [in]  The password received from the EAP client.
  *
  * @param  pwb           [in]  Pointer to the work buffer.
  *
  *
  * @return If the function succeeds, the return value is NO_ERROR.
  */
DWORD 
MakeAuthenticationAttributes(
    IN __in CHAR *   szUserName,    
    IN __in CHAR *   szPassword,    
    IN EAPCB *  pwb
);

/**
  * MakeMPPEKeyAttributes() helper function: Build MPPE Key attributes.
  *
  * @param  pwb           [in]  Pointer to the work buffer.
  *
  * @return If the function succeeds, the return value is NO_ERROR.
  */
DWORD
MakeMPPEKeyAttributes(
    IN EAPCB *  pwb
);


/**
  * FillMppeKeyAttribute() helper function: Construct MPPE Key attributes.
  *
  * This function constructs MPPE encryption key attributes and saves them
  * into the EAPCB work buffer.
  *
  * @return A Win32 error code, indicating success or failure.
  */
DWORD FillMppeKeyAttribute(IN EAPCB *pwb, 
								IN BYTE *&bBuffer, 
								IN DWORD pattern, 
								IN BYTE bKeyDirection,
								IN OUT EapAttribute &pAttrib);


/**
  * Construct a MPPE key vendor attribute.
  *
  * @param   bKeyDirection  [in]  Either MS_MPPE_SEND_KEY or MS_MPPE_RECV_KEY.
  *
  * @param   pMppeKeyData   [in]  The MPPE Key data.
  *
  * @param   cbMppeKeyData  [in]  The byte length of the MPPE Key data.
  *
  * @param   pAttrib        [out] The EAP attribute that will contain the
  *                               final MPPE Key vendor attribute.
  *
  *
  * @return A Win32 error code, indicating success or failure.
  */
DWORD
ConstructMppeKeyAttribute(
    IN     BYTE  bKeyDirection,
    IN     PBYTE pMppeKeyData,
    IN     DWORD cbMppeKeyData,
    IN OUT EapAttribute *pAttrib
);

DWORD 
VerifyAuthenticationAttributes(
      IN EAPCB *pwb);

/**
  * GetIdentity() helper function: Get the username & password for the
  * user to be authenticated.
  *
  * This function obtains credentials for the user being authenticated.
  * It display UI requesting the username & password.
  *
  *
  * @param  hwndParent            [in]  Handle to the parent window for the
  *                                     user interface dialog.
  *
  *
  * @param  ppUserDataOut         [out] Pointer to a pointer that, on
  *                                     successful return, points to the
  *                                     identity data for the user.
  *
  * @param  pdwSizeOfUserDataOut  [out] Pointer to a DWORD variable that
  *                                     receives the size of the data pointed
  *                                     to by the ppUserDataOut parameter.
  *
  *
  * @return If the function succeeds, the return value is NO_ERROR.  
  */
DWORD
GetIdentityAsConfigData(
    IN  HWND    hwndParent,
    OUT BYTE**  ppUserDataOut,
    OUT DWORD*  pdwSizeOfUserDataOut
);

/**
  * GetUsernameAndPassword() helper function: Display user credentials UI.
  *
  * This function displays an interactive UI (the IDD_CONFIG_IDENTITY_DIALOG dialog box)
  * requesting the user to enter their username and password.
  *
  *
  * @param  hwndParent        [in]  Handle to the parent window for the
  *                                 user interface dialog.
  *
  * @param  pEapNameDialog    [in]  Pointer to an EAP_NAME_DIALOG structure
  *                                 that, on successful return, will be filled
  *                                 in with the user's username & password.
  *                                 The caller is responsible for allocating
  *                                 and freeing this buffer.
  *
  *
  * @return If the function succeeds, the return value is NO_ERROR.
  */
DWORD
GetUsernameAndPassword(
    IN  HWND                hwndParent,
    IN  USER_DATA_BLOB*    pEapUserData
);

/**
  * This function handles Windows messages sent to the username/password UI
  * dialog box.  It is called by the Windows UI subsystem.
  *
  * @param  hWnd       [in]  Handle to the dialog box.
  *
  * @param  unMsg      [in]  Specifies the message.  Messages supported:
  *                            \li WM_INITDIALOG -- Initialize the dialog box.
  *                            \li WM_COMMAND -- The user has clicked on a
  *                                menu, control, or has used an accelerator
  *                                key.
  *
  * @param  wParam     [in]  Specifies additional message-specific
  *                          information.
  *
  * @param  lParam     [in]  Specifies additional message-specific
  *                          information.
  *
  *
  * @return The dialog box procedure should return TRUE if it processed the
  *         message, and FALSE if it did not.  If the dialog box procedure
  *         returns FALSE, the dialog manager performs the default dialog
  *         operation in response to the message.
  */
INT_PTR CALLBACK
UsernameDialogProc(
    IN  HWND    hWnd,
    IN  UINT    unMsg,
    IN  WPARAM  wParam,
    IN  LPARAM  lParam
);

/**
  * UsernameDialogProc() helper function: initialize the username dialog.
  *
  * This function handles the WM_INITDIALOG message, by initializing the
  * username dialog.
  *
  *
  * @param  hWnd       [in]  Handle to the dialog box.
  *
  * @param  lParam     [in]  Specifies additional message-specific
  *                          information.
  *
  *
  * @return FALSE, to prevent Windows from setting the default keyboard focus.
  */  

BOOL
InitUsernameDialog(
    IN  HWND    hWnd,
    IN  LPARAM  lParam
);

/**
  *
  * This function handles the WM_COMMAND message, by saving any data the user
  * has entered into the text fields of the username dialog.
  *
  * @param  pEapNameDialog  [in]  Pointer to an EAP_NAME_DIALOG structure
  *                               that, on successful return, will be filled
  *                               in with the user's username & password. This
  *                               buffer must be allocated before this
  *                               function is called.
  *
  * @param  wId             [in]  The identifier of the menu item, control,
  *                               or accelerator.  Supported identifiers:
  *                                 \li IDOK     - the dialog's OK button. The
  *                                     user's credentials will be saved.
  *                                 \li IDCANCEL - the dialog's Cancel button.
  *
  * @param  hWndDlg         [in]  Handle to the dialog box.
  *
  *
  * @return TRUE if we processed this message; FALSE if we did not process
  *         this message.
  */
BOOL
UsernameCommand(
    IN  USER_DATA_BLOB*    pEapUserData,
    IN  WORD                wId,
    IN  HWND                hWndDlg
);

#endif
